﻿using AppWebApi.Models;
using AppWebApi.Models.Dtos;
using AppWebApi.Models.Form;
using AppWebApi.Services;
using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Modules;
using Modules.FaceScan;
using Modules.FaceScan.Entitys;
using Modules.Manager;
using Modules.Person;
using Modules.System.Security;
using Modules.System.User;
using Org.BouncyCastle.Utilities.Encoders;
using PmSoft;
using PmSoft.ApplicationContext;
using PmSoft.Caching.Redis;
using PmSoft.Entity;
using PmSoft.FileStorage;
using static Modules.CheckIn.CheckInDetailConstants;

namespace AppWebApi.Controllers;

/// <summary>
/// App认证相关接口
/// </summary>
[ApiController]
[Route("/api/v1/app")]
public class AuthController : ControllerBase
{
    private readonly CaptchaService captchaService;
    private readonly PersonService personService;
    private readonly FacePhotoService personFaceService;
    private readonly IFileStorage fileStorage;
    private readonly FaceScanRecordService personFaceScanRecordService;
    private readonly SecurityService securityService;
    private readonly AppService appService;
    private readonly IApplicationContext applicationContext;
    private readonly IMapper mapper;
    private static List<VerifyCodeCache> verifyCodeCaches = new List<VerifyCodeCache>();
    private readonly ManagerService managerService;
    private readonly IConfiguration configuration;
    private readonly PmSoftRedisCache redisCache;
    private readonly FaceScanService faceScanService;

    public AuthController(CaptchaService captchaService, PersonService personService, FacePhotoService personFaceService, IFileStorage fileStorage, FaceScanRecordService personFaceScanRecordService, SecurityService securityService, AppService appService, IMapper mapper, IApplicationContext applicationContext, ManagerService managerService, IConfiguration configuration, PmSoftRedisCache redisCache, FaceScanService faceScanService)
    {
        this.captchaService = captchaService;
        this.personService = personService;
        this.personFaceService = personFaceService;
        this.fileStorage = fileStorage;
        this.personFaceScanRecordService = personFaceScanRecordService;
        this.securityService = securityService;
        this.appService = appService;
        this.mapper = mapper;
        this.applicationContext = applicationContext;
        this.managerService = managerService;
        this.configuration = configuration;
        this.redisCache = redisCache;
        this.faceScanService = faceScanService;
    }

    #region 验证码
    /// <summary>
    /// 生成图片验证码
    /// </summary>
    /// <param name="codeType">验证码类型 0：纯数字 1：数字+字母 2：数字运算 默认1</param>
    /// <returns></returns>
    [HttpGet("captcha")]
    public ApiResult<VerifyCodeResult> Captcha(string codeType = "1")
    {
        string uuid = Guid.NewGuid().ToString().Replace("-", "");
        var codeInfo = new VerifyCode();
        if (codeType == "1")
        {
            codeInfo = captchaService.CreateVerifyCode(4, VerifyCodeType.CHAR);
        }
        else if (codeType == "2")
        {
            codeInfo = captchaService.CreateVerifyCode(4, VerifyCodeType.ARITH);
        }
        else if (codeType == "0")
        {
            codeInfo = captchaService.CreateVerifyCode(4, VerifyCodeType.NUM);
        }
        VerifyCodeCache dic = new VerifyCodeCache()
        {
            Id = uuid,
            Code = codeInfo.Code
        };

        verifyCodeCaches.Add(dic);
        VerifyCodeResult verifyCodeResult = new VerifyCodeResult()
        {
            Id = uuid,
            Base64Str = codeInfo.Base64Str
        };
        return ApiResult<VerifyCodeResult>.Success(verifyCodeResult);
    }

    /// <summary>
    /// 检查验证码是否有效
    /// </summary>
    /// <param name="verifyCodeCache"></param>
    /// <returns></returns>
    [HttpPut("captcha_vild")]
    public ApiResult Check(VerifyCodeCache verifyCodeCache)
    {
        var index = verifyCodeCaches.FindIndex(m =>
        {
            if (m.Id.Equals(verifyCodeCache.Id) && m.Code.ToLower().Equals(verifyCodeCache.Code.ToLower()))
            {
                return true;
            }

            return false;
        });

        if (index >= 0)
        {
            verifyCodeCaches.RemoveAt(index);
            return ApiResult.Success("验证成功");
        }
        else
            return ApiResult.Failure("验证失败");
    }
    #endregion

    #region 认证
    /// <summary>
    ///  根据身份证号和密码查询人员信息（劳务员）
    /// </summary>
    /// <param name="req"></param>
    /// <returns></returns>
    [HttpPost("ManagerRealNameVer")]
    public ApiResult<ManagerInfoDto> ManagerRealNameVer([FromBody] EncryptMess req)
    {
        var loginInfo = req.GetCardLoginInfo();
        if (loginInfo == null)
            return ApiResult<ManagerInfoDto>.Failure("参数无法解析");
        if (string.IsNullOrEmpty(loginInfo.CardNumber))
            return ApiResult<ManagerInfoDto>.Failure("请输入身份证号码");
        if (string.IsNullOrEmpty(loginInfo.PassWord))
            return ApiResult<ManagerInfoDto>.Failure("请输入密码");
        if (loginInfo.Type != UserType.Manager)
            return ApiResult<ManagerInfoDto>.Failure("角色只能是劳资专管员");

        ManagerInfo? manager = managerService.PasswordSignIn(loginInfo.CardNumber, SecurityPasswordHelper.EncodePassword(loginInfo.PassWord, UserPasswordFormat.SM3));
        if (manager == null)
            return ApiResult<ManagerInfoDto>.Failure("身份证或密码错误");

        var managerInfoDto = manager.AsDto();
        var security = securityService.GetSysSecurity(manager.SecurityId);
        if (security == null)
            return ApiResult<ManagerInfoDto>.Failure("用户缺少必要信息");

        managerInfoDto.IsAuth = security?.IsAuth ?? false;
        if (managerInfoDto.IsAuth)
            managerInfoDto.Token = appService.GetManagerToken(security.SecurityId, security.UserType, manager.Cardno);

        #region 获取流
        byte[] objectData = personFaceService.GetCardPhotoData(manager.Cardno);
        if (objectData.Length > 0)
            managerInfoDto.Base64PhotoStr = Base64.ToBase64String(objectData);
        #endregion
        var scanRecord = faceScanService.CreateFaceScan(loginInfo.CardNumber, FaceScanReferType.Login, 数据来源.APP);
        managerInfoDto.ScanCode = scanRecord.ScanCode;
        managerInfoDto.Actions = scanRecord.Actions;
        //int actionCheckCount = configuration.GetValue<int>("FaceActionCheckCount", 4);
        //managerInfoDto.Actions = commonService.GetRandFaceActions(actionCheckCount);
        //managerInfoDto.ScanCode = Guid.NewGuid().ToString().Replace("-", "");
        //FaceRecognitionModel faceRecognitionModel = new FaceRecognitionModel()
        //{
        //    CardNumber = loginInfo.CardNumber.ToString(),
        //    Actions = managerInfoDto.Actions,
        //    TimeSpan = DateTime.Now.ToTimeStamp()
        //};
        //  redisCache.Add($"ScanCode:{managerInfoDto.ScanCode}", faceRecognitionModel, TimeSpan.FromMinutes(5));
        return ApiResult<ManagerInfoDto>.Success(managerInfoDto);
    }

    /// <summary>
    /// 根据身份证号查询人员信息（工人）
    /// </summary>
    /// <param name="cardNumber"></param>
    /// <param name="name"></param>
    /// <param name="verifyCode"></param>
    /// <returns></returns>
    [HttpPost("RealNameVer/{cardNumber}")]
    public ApiResult<PersonInfoDto> PersonRealNameVer(string cardNumber, string? name, VerifyCodeCache verifyCode)
    {
        var index = verifyCodeCaches.FindIndex(m =>
        {
            if (m.Id.Equals(verifyCode.Id) && m.Code.ToLower().Equals(verifyCode.Code.ToLower()))
            {
                return true;
            }
            return false;
        });
        if (index < 0)
            return ApiResult<PersonInfoDto>.Failure("验证码错误");
        PersonInfo? personInfo = personService.GetPersonByCardNo(cardNumber);
        if (personInfo == null)
            return ApiResult<PersonInfoDto>.Failure("身份证号不存在");
        if (!string.IsNullOrEmpty(name))
        {
            if (personInfo.Name != name) return ApiResult<PersonInfoDto>.Failure("真实姓名不正确");
        }
        verifyCodeCaches.RemoveAt(index);
        var personInfoDto = personInfo.AsDto();
        #region 获取流
        byte[] objectData = personFaceService.GetCardPhotoData(personInfo.CardNumber);
        if (objectData.Length > 0)
            personInfoDto.Base64PhotoStr = Base64.ToBase64String(objectData);
        #endregion

        var referType = FaceScanReferType.Login;
        if (!string.IsNullOrEmpty(name))
            referType = FaceScanReferType.PersonVerification;

        var scanRecord = faceScanService.CreateFaceScan(cardNumber, referType, 数据来源.APP);
        personInfoDto.Actions = scanRecord.Actions;
        personInfoDto.ScanCode = scanRecord.ScanCode;

        return ApiResult<PersonInfoDto>.Success(personInfoDto);

    }

    /// <summary>
    /// App认证(微信登录)
    /// </summary>
    /// <param name="req"></param>
    /// <returns></returns>
    [HttpPost("wxlogin")]
    public object WXlogin([FromBody] EncryptMess req)
    {
        var loginInfo = req.GetWxLoginInfo();
        if (loginInfo == null)
            return ApiResult.Failure("参数无法解析").Encrypt();
        if (string.IsNullOrEmpty(loginInfo.Unionid) || string.IsNullOrEmpty(loginInfo.OpenId))
            return ApiResult.Failure("微信认证信息不能为空").Encrypt();
        if (string.IsNullOrEmpty(loginInfo.CardNumber))
            return ApiResult.Failure("身份证信息不能为空").Encrypt();
        if (string.IsNullOrEmpty(loginInfo.ScanCode))
            return ApiResult.Failure("人脸识别代码不能为空").Encrypt();
        PersonInfo? personInfo = personService.GetPersonByCardNo(loginInfo.CardNumber);
        if (personInfo == null)
            return ApiResult.Failure("人员不存在").Encrypt();
        if (personInfo.SecurityId.HasValue) return ApiResult.Failure($"人员{loginInfo.CardNumber}已认证，不能重复认证").Encrypt();

        if (!faceScanService.Check(loginInfo.CardNumber, loginInfo.ScanCode, FaceScanReferType.PersonVerification, 数据来源.APP))
            return ApiResult.Failure("未通过人脸识别").Encrypt();

        SecurityEditForm form = new();
        form.LastLoginIp = applicationContext.ClientIp;
        form.LastLoginTime = DateTime.Now;
        form.OpenId = loginInfo.OpenId;
        form.Unionid = loginInfo.Unionid;
        form.UserType = UserType.Worker;
        form.IsAuth = true;
        SysSecurity? sysSecurity = new SysSecurity();
        if (personInfo.SecurityId.HasValue)
            sysSecurity = securityService.GetSysSecurity(personInfo.SecurityId.Value);
        if (sysSecurity?.SecurityId == 0)
        {
            //新增
            sysSecurity = new SysSecurity();
            mapper.Map(form, sysSecurity);
            sysSecurity = securityService.Create(sysSecurity);
        }
        else
        {
            //更新
            sysSecurity.LastLoginIp = applicationContext.ClientIp ?? "";
            sysSecurity.LastLoginTime = DateTime.Now;
            sysSecurity.OpenId = loginInfo.OpenId;
            sysSecurity.Unionid = loginInfo.Unionid;
            sysSecurity.IsAuth = true;
            securityService.Update(sysSecurity);
        }
        personInfo.SecurityId = sysSecurity.SecurityId;
        personService.UpdatePersonInfo(personInfo);
        //生成token
        string token = appService.GetWorkerToken(sysSecurity.SecurityId, form.UserType, loginInfo.CardNumber);
        return ApiResult.Success("成功", token).Encrypt();
    }

    /// <summary>
    /// App认证(身份证登录)
    /// </summary>
    /// <param name="req"></param>
    /// <returns></returns>
    [HttpPost("cardlogin")]
    public object Cardlogin([FromBody] EncryptMess req)
    {
        var loginInfo = req.GetCardLoginInfo();
        if (loginInfo == null)
            return ApiResult.Failure("参数无法解析").Encrypt();
        if (string.IsNullOrEmpty(loginInfo.CardNumber))
            return ApiResult.Failure("身份证信息不能为空").Encrypt();
        if (string.IsNullOrEmpty(loginInfo.ScanCode))
            return ApiResult.Failure("人脸识别代码不能为空").Encrypt();
        string token = "";
        if (loginInfo.Type == UserType.Worker || !loginInfo.Type.HasValue)
        {
            token = appService.WorkerCardLogin(loginInfo);
        }
        else if (loginInfo.Type == UserType.Manager)
        {
            ManagerInfo manager = appService.ManagerCardLogin(loginInfo);
            SysSecurity? sysSecurity = securityService.GetSysSecurity(manager.SecurityId);
            sysSecurity.IsAuth = true;
            securityService.Update(sysSecurity);
            token = appService.GetManagerToken(sysSecurity.SecurityId, sysSecurity.UserType, manager.Cardno);
        }
        return ApiResult.Success("成功", token).Encrypt();
    }

    /// <summary>
    /// 查询是否认证
    /// </summary>
    /// <param name="req"></param>
    /// <returns></returns>
    [HttpPost("IsAuth")]
    public ApiResult IsAuth([FromBody] EncryptMess req)
    {
        var loginInfo = req.GetWxLoginInfo();
        if (loginInfo == null)
            return ApiResult.Failure("参数无法解析").Encrypt();
        if (string.IsNullOrEmpty(loginInfo.Unionid) || string.IsNullOrEmpty(loginInfo.OpenId))
            return ApiResult.Failure("微信认证信息不能为空").Encrypt();
        SysSecurity? sysSecurity = securityService.GetSysSecurityByOpenId(loginInfo.OpenId);
        if (sysSecurity == null)
            return ApiResult.Failure("当前微信还没认证").Encrypt();
        if (sysSecurity.Unionid != loginInfo.Unionid || sysSecurity.IsAuth != true)
            return ApiResult.Failure("当前微信还没认证").Encrypt();

        PersonInfo? personInfo = personService.GetPersonBySecurityId(sysSecurity.SecurityId);
        if (personInfo == null)
            return ApiResult.Failure("人员信息查询失败").Encrypt();
        //生成token
        string token = appService.GetWorkerToken(sysSecurity.SecurityId, sysSecurity.UserType, personInfo.CardNumber);

        //int actionCheckCount = configuration.GetValue<int>("FaceActionCheckCount", 4);
        //FaceRecognitionModel faceRecognitionModel = new FaceRecognitionModel()
        //{
        //    ScanCode = Guid.NewGuid().ToString().Replace("-", ""),
        //    CardNumber = personInfo.CardNumber,
        //    Actions = commonService.GetRandFaceActions(actionCheckCount),
        //    Token = token,
        //    TimeSpan = DateTime.Now.ToTimeStamp()
        //};
        //redisCache.Add($"ScanCode:{faceRecognitionModel.ScanCode}", faceRecognitionModel, TimeSpan.FromMinutes(5));
        return ApiResult.Success("已认证", token).Encrypt();
    }

    #endregion


}
